package net.openl10n.packaging;

import java.util.HashMap;
import java.util.Map;

import net.openl10n.opc4j.PackagePart;

public class OpenLocPartFactoryManager{
	
	private Map<Class<? extends OpenLocPart>, OpenLocPartFactory<?>> classFactories;
	private Map<String, OpenLocPartFactory<?>> contentTypeFactories;
	private Map<String, String> partPrefixes;
	private Map<String, OpenLocPartFactoryManager> managers;
	
	public OpenLocPartFactoryManager() {
		classFactories = new HashMap<Class<? extends OpenLocPart>, OpenLocPartFactory<?>>();
		contentTypeFactories = new HashMap<String, OpenLocPartFactory<?>>(); 
		partPrefixes = new HashMap<String, String>();
		managers = new HashMap<String, OpenLocPartFactoryManager>();
	}
	
	public OpenLocPartFactoryManager(OpenLocPartFactoryManager parent) {
		classFactories = new HashMap<Class<? extends OpenLocPart>, OpenLocPartFactory<?>>(parent.classFactories);
		contentTypeFactories = new HashMap<String, OpenLocPartFactory<?>>(parent.contentTypeFactories); 
		partPrefixes = new HashMap<String, String>(parent.partPrefixes);
		managers = new HashMap<String, OpenLocPartFactoryManager>(parent.managers);
	}
	
	public void registerManager(String contentType, OpenLocPartFactoryManager manager){
		managers.put(contentType, manager);
	}
	
	private OpenLocPartFactoryManager getManagerForContentType(String contentType){
		OpenLocPartFactoryManager manager = managers.get(contentType);
		return manager == null ? this : manager;
	}
	
	@SuppressWarnings("unchecked")
	public <T extends OpenLocPart> OpenLocPartFactory<T> get(Class<T> clz){
		return (OpenLocPartFactory<T>) classFactories.get(clz);
	}

	public OpenLocPartFactory<?> getX(Class<?> clz){
		return classFactories.get(clz);
	}
	
	public <T extends OpenLocPart> void add(OpenLocPartFactory<T> factory){
		classFactories.put(factory.getTargetClass(), factory);
		contentTypeFactories.put(factory.getContentType(), factory);
	}

	public void remove(OpenLocPartFactory<?> factory){
		classFactories.remove(factory.getTargetClass());
		contentTypeFactories.remove(factory.getContentType());
	}
	public void remove(String contentType){
		OpenLocPartFactory<?> factory = contentTypeFactories.get(contentType);
		if(factory != null){
			contentTypeFactories.remove(contentType);
			classFactories.remove(factory.getTargetClass());
		}
	}
	
	public OpenLocPart create(OpenLocPartContainer container, PackagePart part){
		OpenLocPartFactory<?> factory = contentTypeFactories.get(part.getContentType());
		if(factory == null){
			return new ExtendedPart(container, part, getManagerForContentType(part.getContentType()));
		}
		return factory.create(container, part,getManagerForContentType(part.getContentType()));
	}

	public <T extends OpenLocPart> T create(Class<T> clz, OpenLocPartContainer container, PackagePart part){
		OpenLocPartFactory<?> factory = contentTypeFactories.get(part.getContentType());
		if(factory == null){
			return clz.cast(new ExtendedPart(container, part, getManagerForContentType(part.getContentType())));
		}
		return clz.cast(factory.create(container, part, getManagerForContentType(part.getContentType())));
	}

	public void setPrefix(String contentType, String prefix){
		partPrefixes.put(contentType, prefix);
	}
	
	public String getPrefix(String contentType){
		String prefix = partPrefixes.get(contentType);
		return prefix == null ? "" : prefix;
	}
	
}
